/**
 * 
 */
package common.project.epic.core;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.protocol.HTTP;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.util.Log;

import common.project.epic.db.CurrentUser;
import common.project.epic.db.EpicDBAdapter;

/**
 * @author luca vidale
 *
 */
public class EpicSynch extends Service {

	
	private static final String SEND_CONTENTS_HTTP_URL = "http://epic.vidaleluca.com/contentuploader.php";
	private static final String SEND_META_HTTP_URL = "http://epic.vidaleluca.com/getmetacontents.php";
	private static final String SEND_ATTACHMENTS_HTTP_URL = "http://epic.vidaleluca.com/sendAttachments.php";
	private static final String UPDATE_RANK_HTTP_URL = "http://epic.vidaleluca.com/updaterank.php";
	private static final String NEGOTIATE_CONTENTS_UPLOAD_HTTP_URL = "http://epic.vidaleluca.com/negotiate_content.php";
	private static EpicDBAdapter mDBAdapter;
	private static int mStartMode = START_STICKY;
	private static EpicSynchBR mBr;
	private static Timer synch_timer;
	private static Context mContext;
	public static boolean IS_SYNCHING;
    
	
	@Override
    public void onCreate() {
//		android.os.Debug.waitForDebugger();
		mContext = getApplicationContext();
		mDBAdapter = new EpicDBAdapter(mContext);
		//create synch timer and schedulate the timer task
		IS_SYNCHING = false;
		synch_timer = new Timer();
		SynchTask st = new SynchTask();
		if(isOnline()){
			st.run();
		}
		synch_timer.scheduleAtFixedRate(st, 0, 10*60*1000);//every ten minutes
		IS_SYNCHING = true;
		IntentFilter iFilter = new IntentFilter();
		iFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
		mBr = new EpicSynchBR();
		registerReceiver(mBr, iFilter);
		
    }

	
//	@Override
//    public int onStartCommand(Intent intent, int flags, int startId) {
//		return mStartMode;
//		
//    }
	
	public class SynchTask extends TimerTask{
		@Override
		public void run() {
			if(isOnline()){
				String contents = prepareAllMetaToJSON();
				if(contents==null||contents.equals("")){
					Log.d("EPIC SYNCH","All the contents are already synched");
				}
				else{
					JSONMetaUploader jsonUp = new JSONMetaUploader(contents, SEND_META_HTTP_URL, null);
					jsonUp.run();
					JSONContentNegotiate jsonNeg = new JSONContentNegotiate(NEGOTIATE_CONTENTS_UPLOAD_HTTP_URL, prepareAllContentsToJSON());
					jsonNeg.run();
				}
			}
		}
	}
	
	public class EpicSynchBR extends BroadcastReceiver{
		@Override
		public void onReceive(Context context, Intent intent) {
			String action = intent.getAction();
			if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION))
			{
			  NetworkInfo info = (NetworkInfo)intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
			  if (info.getState().equals(NetworkInfo.State.CONNECTED))
			  {
				  if(!IS_SYNCHING ){
				  	synch_timer = new Timer();
					SynchTask st = new SynchTask();
					if(isOnline()){
						st.run();
					}
					synch_timer.scheduleAtFixedRate(st, 0, 2*60*1000);//every ten minutes
					IS_SYNCHING = true;
				  }
//						String contents = prepareAllMetaToJSON();
//						JSONMetaUploader jsonUp = new JSONMetaUploader(contents, SEND_META_HTTP_URL, null);
//						jsonUp.run();
//						JSONContentNegotiate jsonNeg = new JSONContentNegotiate(NEGOTIATE_CONTENTS_UPLOAD_HTTP_URL, prepareAllContentsToJSON());
//						jsonNeg.run();
//						rescheduleSynch();
			  	}
			}
		}
	}
	
	@Override
	public void onDestroy(){
		
		if(mBr!= null){
			getApplicationContext().unregisterReceiver(mBr);
		}
	}
	
	public class  SynchTT extends TimerTask{

		@Override
		public void run() {
			//
			if(isOnline()){
				
			}else{
				rescheduleSynch();
			}
			
		}
		
	}
	
	
	public boolean isOnline() {
		ConnectivityManager cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
		NetworkInfo ni = cm.getActiveNetworkInfo();
		if(ni != null){
			return cm.getActiveNetworkInfo().isConnectedOrConnecting();
		}
		else {
			return false;
		}
	}
	public void rescheduleSynch() {
		SynchTT synch_task = new SynchTT();
		Timer synch_timer = new Timer();
		synch_timer.schedule(synch_task,1000*60*30);
		
	}
	//put all contents to a JSON Array (not only meta but ALL the content)
	public JSONArray prepareAllContentsToJSON() {
		JSONArray jsonArray = new JSONArray();
		try {
			
			mDBAdapter.open();
			Cursor single_content_cursor = mDBAdapter.getNotSynchContents();
			mDBAdapter.close();
			if(single_content_cursor!=null) {
				if (single_content_cursor.getCount()!=0){
				
					single_content_cursor.moveToFirst();
					int n_contents = single_content_cursor.getCount();
					
							for(int i=0; i<n_contents; i++) {
							JSONObject jsonObj = new JSONObject();
							
							//set the JSONObj from the single row
							//EPIC msg id
							jsonObj.put(Integer.toString(single_content_cursor.getPosition()), 
									single_content_cursor.getString(1) + ";" + single_content_cursor.getString(2) + ";" 
									+ single_content_cursor.getString(3) + ";" + single_content_cursor.getString(4) + ";" 
									+ single_content_cursor.getString(5) + ";" + single_content_cursor.getString(6) + ";"
									+ single_content_cursor.getString(23) + ";" + single_content_cursor.getString(24) + ";" 
									+ single_content_cursor.getString(25) + ";" + single_content_cursor.getString(7) + ";"
									+ single_content_cursor.getString(8) + ";" + single_content_cursor.getString(9) + ";" 
									+ single_content_cursor.getString(10) + ";" + single_content_cursor.getString(11));
							//add the JSON obj to JSON Array
							jsonArray.put(jsonObj);
							single_content_cursor.moveToNext();
						}	
				}
			}
			return jsonArray;
		}
			
		 catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
		
		
	}
	
	public String prepareAllMetaToJSON() {
		JSONArray jsonArray = new JSONArray();
		try {
			mDBAdapter.open();
			Cursor cursor = mDBAdapter.getNotSynchContents();
			mDBAdapter.close();
			if(cursor!=null) {
				if (cursor.getCount()!=0){
				
				cursor.moveToFirst();
				int n_contents = cursor.getCount();
						
					for(int i=0; i<n_contents; i++) {
						
							JSONObject jsonObj = new JSONObject(); 
							//set the JSONObj from the single row
							//EPIC msg id
							jsonObj.put(Integer.toString(cursor.getPosition()), 
									cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_ID)) + ";" + cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_DEL_ID)) + ";" 
											+ cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_DEL_TIME)) + ";" + cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_DEL_LAT)) + ";" 
											+ cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_DEL_LON)) + ";" + cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_DEL_ALT))
											+ cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_COPY_RATE)) + ";");
							cursor.moveToNext();
							jsonArray.put(jsonObj);
							
						}
				
				String contents = jsonArray.toString();
				return contents;
				
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
		return null;
		
	}
	
	public String prepareAllRankToJSON() {
		JSONArray jsonArray = new JSONArray();
		try {
			mDBAdapter.open();
			Cursor cursor = mDBAdapter.getNotUpdatedContents();
			mDBAdapter.close();
			if(cursor!=null) {
				if (cursor.getCount()!=0){
				
				cursor.moveToFirst();
				int n_contents = cursor.getCount();
						
					for(int i=0; i<n_contents; i++) {
						
							JSONObject jsonObj = new JSONObject(); 
							//set the JSONObj from the single row
							//EPIC msg id
							jsonObj.put(Integer.toString(cursor.getPosition()), 
									cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_ID)) + ";" + cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_COPY_RATE)) + ";" 
									+ cursor.getString(cursor.getColumnIndex(EpicDBAdapter.CREATOR_NICK_NAME)) + ";" + cursor.getString(cursor.getColumnIndex(EpicDBAdapter.MSG_HOP_COUNTER)) + ";" 
									);
							cursor.moveToNext();
							jsonArray.put(jsonObj);
							
						}
				
				String contents = jsonArray.toString();
				return contents;
				
				}
			}
		} catch (JSONException e) {
			e.printStackTrace();
			return null;
		}
		return null;
		
	}
	
	//Thread that negotiate what contents to Upload to the server
	public class JSONContentNegotiate extends Thread{
	   
	    private String url;
	    private JSONArray json_arr;
	    Reader r;
	    
	    public JSONContentNegotiate( String url, JSONArray json_arr){
	        this.url=url;
	        this.json_arr = json_arr;
	    }
	    
	    @Override
	    public void run() {
	        upload();
	    }
	    
	    private void upload() {
	    	
	    	try{
		    	HttpClient client =  new DefaultHttpClient();
			    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
			    HttpPost post = new HttpPost(this.url);
	            HttpResponse response;
			    InputStream data = null;
			    Log.d("JSON RESPONSE", "EPIC Synch is negotiating the transfer of following content: "+ json_arr.toString());
			    String[] msgid_arr = new String[json_arr.length()];
			    JSONArray json_msgid_arr = new JSONArray();
				    
			    	for(int i = 0; i < json_arr.length(); i++){
					    	JSONObject obj =  new JSONObject();
					    	obj =  (JSONObject) json_arr.get(i);
					    	String[] element_string = obj.getString(Integer.toString(i)).split(";");
					    	String msgid = element_string[0];
					    	msgid_arr[i] = msgid;
					    	JSONObject msgid_obj = new JSONObject();
					    	msgid_obj.put(Integer.toString(i), msgid);
					    	json_msgid_arr.put(msgid_obj);
				    }
				
			    String content = json_msgid_arr.toString();
	            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
	            nvps.add(new BasicNameValuePair("json", content));
	            post.setHeader("Content-Type", "application/x-www-form-urlencoded");
	            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
	            response = client.execute(post);
	            data = response.getEntity().getContent();
	            r = new InputStreamReader(data);
	            StringBuffer buffer = new StringBuffer();
	            Reader in = new BufferedReader(r);
	            int ch;
		            while ((ch = in.read()) > -1) {
		                buffer.append((char) ch);
		            }
	            
	            in.close();
	            Log.d("JSON RESPONSE", "SERVER RESPOND WITH: " + buffer.toString());
	            char[] ispresent = buffer.toString().toCharArray();
	            int q = 0;
//	            synch_increment = Math.round(100/ispresent.length);
//	            synch_padd = 100 - (synch_increment * ispresent.length);
//	            synch_percentage = synch_percentage + synch_padd;
	            
			    for(char ispresent_element : ispresent){
		            if(ispresent_element == '0'){
				    	//send content
		            	Log.d("JSON RESPONSE", "EPIC SYNCH is sending content with msgid: "+ msgid_arr[q]);
		            	JSONContentUploader contentuploader = new JSONContentUploader(msgid_arr[q], SEND_CONTENTS_HTTP_URL);
		            	contentuploader.run();
				    }else if(ispresent_element == '1'){
				    	Log.d("JSON RESPONSE", "EPIC SYNCH don't send content with msgid: "+ msgid_arr[q-1]);
				    }
				    
		            q = q+1;
			    }
			    //rischedula il synch
			    rescheduleSynch();
			    
		    } catch (Exception e) {
		    	e.printStackTrace();
		    	}
	    }
	 
	}

	//upload a single content
	public class JSONContentUploader extends Thread{
	    private String msgid;
	    private String url;
	    
	    Reader r;
	    
	    public JSONContentUploader(String msgid, String url){
	        this.url = url;
	        this.msgid = msgid;
	    }
	    
	    @Override
	    public void run() {
	        // TODO Auto-generated method stub
	        upload();
	    }
	    private void upload() {
	    	try{
	    	HttpClient client =  new DefaultHttpClient();
		    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
		    HttpPost post = new HttpPost(this.url);
            HttpResponse response;
            mDBAdapter.open();
            Cursor single_content_cursor = mDBAdapter.getContent(this.msgid);
            mDBAdapter.close();
            //set the JSONObj from the single row
			//EPIC msg id
            single_content_cursor.moveToFirst();
            JSONArray jsonArray = new JSONArray();
            JSONObject jsonObj = new JSONObject();
			jsonObj.put(Integer.toString(single_content_cursor.getPosition()), 
					single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_ID)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_EXP_TIME)) + ";" 
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_GEO_LAT)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_GEO_LON)) + ";" 
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_GEO_ALT)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_GEO_SPAN)) + ";"
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CREATOR_ID)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_TITLE)) + ";" 
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CONTENT)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CATEGORY_GAMES)) + ";"
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CATEGORY_ADVERTISEMENTS)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CATEGORY_SUGGESTIONS)) + ";" 
					+ single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CATEGORY_EVENTS)) + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_CATEGORY_GENERAL)) 
					+ ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.CREATOR_NICK_NAME))  + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_HOP_COUNTER))
					+ ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MY_RATE))  + ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.MSG_COPY_RATE))
					+ ";" + single_content_cursor.getString(single_content_cursor.getColumnIndex(EpicDBAdapter.TC_NUMBER))+ ";" + CurrentUser.getMd5ID(getApplicationContext()));
			//add the JSON obj to JSON Array
			Log.d("JSON UPLOAD FOLLOW CONTENT:", ""+ jsonObj.toString());
			jsonArray.put(jsonObj);
		    InputStream data = null;
            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
            nvps.add(new BasicNameValuePair("json", jsonArray.toString()));
            post.setHeader("Content-Type", "application/x-www-form-urlencoded");
            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
            
            //parse server response
            response = client.execute(post);
            data = response.getEntity().getContent();
            r = new InputStreamReader(data);
            StringBuffer buffer = new StringBuffer();
            Reader in = new BufferedReader(r);
            int ch;
	            while ((ch = in.read()) > -1) {
	                buffer.append((char) ch);
	            }
	        
	        //Set synch_notsynch flag
            mDBAdapter.open();
            mDBAdapter.markAsSynched(this.msgid);
			mDBAdapter.close();        
//            synch_percentage = synch_percentage + synch_increment;
            in.close();
            Log.d("JSON RESPONSE", "EPIC WEB SERVER received uploaded content ");
		    } catch (Exception e) {
		    	e.printStackTrace();
		    }
	 
	    }
	 
	}
	
	//used to get the missing contents server string response and then you must use JSONContent Uploader class to upload server missing contents
	public class JSONMetaContentsUploader extends Thread{
	    //meta contents string
		private String contents;
	    private String url;
	    
	    Reader r;
	    
	    public JSONMetaContentsUploader(String contents, String url){
	        this.url=url;
	        this.contents = contents;
	        
	    }
	    
	    @Override
	    public void run() {
	        upload();
	    }
	    private void upload() {
	    	
	    	try {
			    	HttpClient client =  new DefaultHttpClient();
				    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
				    HttpPost post = new HttpPost(this.url);
		            HttpResponse response;
		              
				    InputStream data = null;
		            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
		            nvps.add(new BasicNameValuePair("json", contents));
		            CurrentUser.readCurrentUserSettings(getApplicationContext());
		            String username = CurrentUser.getCurrentUsername();
		            nvps.add(new BasicNameValuePair("username", username));
		            post.setHeader("Content-Type", "application/x-www-form-urlencoded");
		            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
		            response = client.execute(post);
		            data = response.getEntity().getContent();
		            r = new InputStreamReader(data);
		            StringBuffer buffer = new StringBuffer();
		            Reader in = new BufferedReader(r);
		            int ch;
			            while ((ch = in.read()) > -1) {
			                buffer.append((char) ch);
			            }
		            in.close();
		            
		            
		    } catch (Exception e) {
		    	
		    		e.printStackTrace();
		    	}
	 
	    }
	}

	 
	
	public class JSONMetaUploader extends Thread{
	    private String contents;
	    private String url;
	    private JSONArray json_obj_arr;
	    Reader r;
	    
	    public JSONMetaUploader(String contents, String url, JSONArray json_arr){
	        this.url=url;
	        this.contents = contents;
	        this.json_obj_arr = json_arr;
	    }
	    
	    @Override
	    public void run() {
	        
	        upload();
	    }
	    private void upload() {
	    	
	    	try {
			    	HttpClient client =  new DefaultHttpClient();
				    HttpConnectionParams.setConnectionTimeout(client.getParams(), 10000);
				    HttpPost post = new HttpPost(this.url);
		            HttpResponse response;
		              
				    InputStream data = null;
		            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
		            nvps.add(new BasicNameValuePair("json", contents ));
		            CurrentUser.readCurrentUserSettings(getApplicationContext());
		            String username = CurrentUser.getCurrentUsername();
		            nvps.add(new BasicNameValuePair("username", username));
		            post.setHeader("Content-Type", "application/x-www-form-urlencoded");
		            post.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
		            response = client.execute(post);
		            data = response.getEntity().getContent();
		            r = new InputStreamReader(data);
		            StringBuffer buffer = new StringBuffer();
		            Reader in = new BufferedReader(r);
		            int ch;
			            while ((ch = in.read()) > -1) {
			                buffer.append((char) ch);
			            }
		            in.close();
		            
		    } catch (Exception e) {
		    	
		    		e.printStackTrace();
		    	}
	 
	    }
	 
	}
	
	
	public class FileUploader extends Thread{
	    private File f;
	    private String url;
	    public FileUploader(Uri u,String url){
	        this.url=url;
	        this.f= new File(u.getPath());
	    }
	    @Override
	    public void run() {
	        // TODO Auto-generated method stub
	        upload();
	    }
	    private void upload() {
	 
	        HttpClient httpclient = new DefaultHttpClient();
	        HttpPost httppost = new HttpPost(url);
	 
	        try {
	            MultipartEntity entity = new MultipartEntity();
	 
	            entity.addPart("user", new StringBody(CurrentUser.getCurrentUsername()));
	            entity.addPart("password", new StringBody(CurrentUser.getCurrentPassword()));
	            entity.addPart("data", new FileBody(f));
	            httppost.setEntity(entity);
	            HttpResponse response = httpclient.execute(httppost);
	        }
	        catch (ClientProtocolException e) {
	            Log.d("[Jin]", e.getMessage(),e);
	        }
	        catch (IOException e) {
	            Log.d("[Jin]", e.getMessage(),e);
	        }
	 
	    }
	 
	}


	//generate md5 digest
	//@params String

	private String md5(String in) {
        MessageDigest digest;
        try {
            digest = MessageDigest.getInstance("MD5");
            digest.reset();        
            digest.update(in.getBytes());
            byte[] a = digest.digest();
            int len = a.length;
            StringBuilder sb = new StringBuilder(len << 1);
            for (int i = 0; i < len; i++) {
                sb.append(Character.forDigit((a[i] & 0xf0) >> 4, 16));
                sb.append(Character.forDigit(a[i] & 0x0f, 16));
            }
            return sb.toString();
        } catch (NoSuchAlgorithmException e) { e.printStackTrace(); }
        return null;
    }


	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
}


